package com.developer.logic.modulo.partidos;

import java.util.ArrayList;
import java.util.List;

import org.apache.ibatis.session.SqlSession;

import com.developer.core.utils.SimpleLogger;
import com.developer.logic.modulo.equipos.EquipoServicio;
import com.developer.logic.modulo.equipos.dto.Equipo;
import com.developer.logic.modulo.equipos.dto.Jugador;
import com.developer.logic.modulo.general.ParametrizacionServicio;
import com.developer.logic.modulo.general.dto.Sede;
import com.developer.logic.modulo.grupos.GrupoServicio;
import com.developer.logic.modulo.grupos.dto.Grupo;
import com.developer.logic.modulo.partidos.dto.AlineacionPartido;
import com.developer.logic.modulo.partidos.dto.CambioPartido;
import com.developer.logic.modulo.partidos.dto.FaltaPartido;
import com.developer.logic.modulo.partidos.dto.GolesPartido;
import com.developer.logic.modulo.partidos.dto.Partido;
import com.developer.logic.modulo.partidos.dto.PartidoJuez;
import com.developer.logic.modulo.partidos.dto.TarjetasPartido;
import com.developer.logic.modulo.partidos.dto.TirosPartido;
import com.developer.mybatis.DBManager;
import com.developer.persistence.modulo.partidos.PartidoControllerDB;

public class PartidoServicio {
	
	private static PartidoServicio instance;
	
	public static PartidoServicio getInstance() {
		if (instance == null) {
			instance = new PartidoServicio();
		}
		
		return instance;
	}
			
	public List<Partido> getPartidosPorGrupo(Grupo grupo){
		
		PartidoControllerDB controllerDB = PartidoControllerDB.getInstance();
		List<Partido> listaPartidos= controllerDB.getPartidosPorGrupo(grupo);
		
		if(listaPartidos!= null && listaPartidos.size()>0){
			
			for (Partido partidoConsultado : listaPartidos) {
				completarInformacionPartido(partidoConsultado);
			}
			
			
		}
		
		
		return listaPartidos;
	}
	
	public List<Partido> getPartidosPorGrupoPorProgramar(Grupo grupo){
		
		PartidoControllerDB controllerDB = PartidoControllerDB.getInstance();
		List<Partido> listaPartidos= controllerDB.getPartidosPorGrupoPorProgramar(grupo);
		
		if(listaPartidos!= null && listaPartidos.size()>0){
			
			for (Partido partidoConsultado : listaPartidos) {
				completarInformacionPartido(partidoConsultado);
			}
			
			
		}
		
		
		return listaPartidos;
	}
	
	public List<Partido> getPartidosPorGrupoSinFinalizar(Grupo grupo){
		
		PartidoControllerDB controllerDB = PartidoControllerDB.getInstance();
		List<Partido> listaPartidos= controllerDB.getPartidosPorGrupoSinFinalizar(grupo);
		
		if(listaPartidos!= null && listaPartidos.size()>0){
			
			for (Partido partidoConsultado : listaPartidos) {
				completarInformacionPartido(partidoConsultado);
			}
			
			
		}
		
		
		return listaPartidos;
	}
	
	
	public Partido getPartido(Long partido){
		
		PartidoControllerDB controllerDB = PartidoControllerDB.getInstance();
		Partido partidoConsultado= controllerDB.getPartido(partido);
		
		if(partidoConsultado!= null){
			
			completarInformacionPartido(partidoConsultado);
		}
		
		
		return partidoConsultado;
	}
	
	
	public Boolean registrarInfoPartido(Partido partido, 
										List<GolesPartido> golesPartidoEquipoUno, 
										List<GolesPartido> golesPartidoEquipoDos,
										List<TarjetasPartido> tarjetasPartidoEquipoUno,
										List<TarjetasPartido> tarjetasPartidoEquipoDos, StringBuffer mensajeError){
		
		SqlSession session = DBManager.openSession();
		
		try {
			
		
			Boolean sinErrores = true;
			int totalGolesEquipoUno=0;
			int totalGolesEquipoDos=0;
			
			
			//Se registran los goles del partido
			for (GolesPartido golPartidoEquipoUno : golesPartidoEquipoUno) {
				
				if(	golPartidoEquipoUno.getJugador()!=null && 
					golPartidoEquipoUno.getMinuto()!=null && 
					golPartidoEquipoUno.getTipo_tiro()!=null ){
					
					golPartidoEquipoUno.setPartido(partido.getPartido());
					
					golPartidoEquipoUno = crearGolesPartidoTransaccional(session, golPartidoEquipoUno, mensajeError);
					
					if(golPartidoEquipoUno==null){
						sinErrores=false;
					}else{
						totalGolesEquipoUno++;
					}
				}
			}
			
			
			
			for (GolesPartido golPartidoEquipoDos : golesPartidoEquipoDos) {
				
				if(	golPartidoEquipoDos.getJugador()!=null && 
						golPartidoEquipoDos.getMinuto()!=null && 
						golPartidoEquipoDos.getTipo_tiro()!=null ){
			
					golPartidoEquipoDos.setPartido(partido.getPartido());
						
					golPartidoEquipoDos = crearGolesPartidoTransaccional(session, golPartidoEquipoDos, mensajeError);
					
					
					
					if(golPartidoEquipoDos==null){
						sinErrores=false;
					}else{
						totalGolesEquipoDos++;
					}
				}
			}
			
			
			//Se revisa la asignacion de puntos y la cantidad de goles sean correctos
			if(partido.getPuntos_1().equals(Partido.PUNTOS_GANADOR)){
				if(totalGolesEquipoUno<=totalGolesEquipoDos){
					sinErrores =false;
					mensajeError.append("El equipo ganador no puede tener menos o igual número de goles que el equipo perdedor");
					
				}else if(!partido.getPuntos_2().equals(Partido.PUNTOS_PERDEDOR)){
					sinErrores =false;
					mensajeError.append("El equipo perdedor solo puede obtener un puntaje de: "+Partido.PUNTOS_PERDEDOR);
					
				}
				
			
			}else if(partido.getPuntos_2().equals(Partido.PUNTOS_GANADOR)){
				if(totalGolesEquipoDos<=totalGolesEquipoUno ){
					sinErrores= false;
					mensajeError.append("El equipo ganador no puede tener menos o igual número de goles que el equipo perdedor");
					
				}else if(!partido.getPuntos_1().equals(Partido.PUNTOS_PERDEDOR)){
					sinErrores =false;
					mensajeError.append("El equipo perdedor solo puede obtener un puntaje de: "+Partido.PUNTOS_PERDEDOR);
					
				}
				
			}else if( (partido.getPuntos_1().equals(Partido.PUNTOS_EMPATE) && !partido.getPuntos_2().equals(Partido.PUNTOS_EMPATE)) ||
					  (partido.getPuntos_2().equals(Partido.PUNTOS_EMPATE) && !partido.getPuntos_1().equals(Partido.PUNTOS_EMPATE)) ){
				
				sinErrores =false;
				mensajeError.append("Si hubo empate ambos equipos deben obtener un puntaje de: "+Partido.PUNTOS_EMPATE);
				
			}
			
			
			//Se registran las tarjetas del partido
			if(sinErrores){
				for (TarjetasPartido tarjetaPartidoEquipoUno : tarjetasPartidoEquipoUno) {
					
					if(	tarjetaPartidoEquipoUno.getJugador()!=null && 
						tarjetaPartidoEquipoUno.getMinuto()!=null && 
						tarjetaPartidoEquipoUno.getTipo_tarjeta()!=null ){
						
						tarjetaPartidoEquipoUno.setPartido(partido.getPartido());
						
						tarjetaPartidoEquipoUno = crearTarjetasPartidoTransaccional(session, tarjetaPartidoEquipoUno, mensajeError);
					
						if(tarjetaPartidoEquipoUno==null){
							sinErrores=false;
						}
					}
				}	
				
				for (TarjetasPartido tarjetaPartidoEquipoDos : tarjetasPartidoEquipoDos) {
					
					if(	tarjetaPartidoEquipoDos.getJugador()!=null && 
						tarjetaPartidoEquipoDos.getMinuto()!=null && 
						tarjetaPartidoEquipoDos.getTipo_tarjeta()!=null ){
						
						tarjetaPartidoEquipoDos.setPartido(partido.getPartido());
						
						tarjetaPartidoEquipoDos = crearTarjetasPartidoTransaccional(session, tarjetaPartidoEquipoDos, mensajeError);
						
						if(tarjetaPartidoEquipoDos==null){
							sinErrores=false;
						}
					}
				}
				
			}
			
			//Se cambia el estado del partido a FINALIZADO
			if(sinErrores){
				partido.setEstado(Partido.ESTADO_FINALIZADO);
				sinErrores = PartidoControllerDB.getInstance().finalizarPartidoTransaccional(session, partido)&& sinErrores;
				
			}
			
			
			//Si no existen errores se finaliza la transaccion
			if(sinErrores){
				
				session.commit();
			}else{
				session.rollback();
			}
			
			
			return sinErrores;
			
		}catch (Exception e) {
			session.rollback();
			SimpleLogger.error("Error ", e);
			mensajeError.append("Error creando grupo. No se ha podido finalizar correctamente.");
			
			return false;
			
			
		} 	finally {
			session.close();
		}	
		
		
	}
	
	
	
	/**
	 * Se crea AlineacionPartido  
	 * 
	 * @param session
	 * @param alineacionPartido
	 * @param mensajeError
	 * @return
	 */
	
	private AlineacionPartido crearAlineacionPartidoTransaccional(SqlSession session, AlineacionPartido alineacionPartido, StringBuffer mensajeError){
		
		try {
			
			Boolean sinErrores = true;
			
			Long idAlineacionPartido = PartidoControllerDB.getInstance().getSiguienteIDPartidoTransaccional(session);
			alineacionPartido.setPartido(idAlineacionPartido);
			
			sinErrores = PartidoControllerDB.getInstance().crearAlineacionPartidoTransaccional(session, alineacionPartido) && sinErrores;
			
			if(sinErrores){
				
				return alineacionPartido;
			}else{
				
				mensajeError.append("Error creando el alineacionPartido.");
				return null;
			}

		}catch (Exception e) {
			session.rollback();
			SimpleLogger.error("Error ", e);
			mensajeError.append("Error creando AlienacionPartido. No se ha podido finalizar correctamente.");
			
			return null;
			
			
		} 	
		
		
		
	}
	
	/**
	 * Se crea cambioPartido
	 * 
	 * @param session
	 * @param cambioPartido
	 * @param mensajeError
	 * @return
	 */
	
	private CambioPartido crearCambioPartidoTransaccional(SqlSession session, CambioPartido cambioPartido, StringBuffer mensajeError){
		
		try {
			
			Boolean sinErrores = true;
			
			Long idCambioPartido = PartidoControllerDB.getInstance().getSiguienteIDCambioPartidoTransaccional(session);
			cambioPartido.setPartido(idCambioPartido);
			
			sinErrores = PartidoControllerDB.getInstance().crearCambioPartidoTransaccional(session, cambioPartido) && sinErrores;
			
			if(sinErrores){
				
				return cambioPartido;
			}else{
				
				mensajeError.append("Error creando el cambioPartido.");
				return null;
			}

		}catch (Exception e) {
			session.rollback();
			SimpleLogger.error("Error ", e);
			mensajeError.append("Error creando cambioPartido. No se ha podido finalizar correctamente.");
			
			return null;
			
			
		} 	
		
		
		
	}
	
	/**
	 * Se crea faltaPartido
	 * 
	 * @param session
	 * @param faltaPartido
	 * @param mensajeError
	 * @return
	 */
	
	private FaltaPartido crearFaltaPartidoTransaccional(SqlSession session, FaltaPartido faltaPartido, StringBuffer mensajeError){
		
		try {
			
			Boolean sinErrores = true;
			
			Long idFaltaPartido = PartidoControllerDB.getInstance().getSiguienteIDFaltaPartidoTransaccional(session);
			faltaPartido.setPartido(idFaltaPartido);
			
			sinErrores = PartidoControllerDB.getInstance().crearFaltaPartidoTransaccional(session, faltaPartido) && sinErrores;
			
			if(sinErrores){
				
				return faltaPartido;
			}else{
				
				mensajeError.append("Error creando el faltaPartido.");
				return null;
			}

		}catch (Exception e) {
			session.rollback();
			SimpleLogger.error("Error ", e);
			mensajeError.append("Error creando faltaPartido. No se ha podido finalizar correctamente.");
			
			return null;
			
			
		} 	
		
		
		
	}
	
	/**
	 * Se crea golesPartido
	 * 
	 * @param session
	 * @param golesPartido
	 * @param mensajeError
	 * @return
	 */
	
	private GolesPartido crearGolesPartidoTransaccional(SqlSession session, GolesPartido golesPartido, StringBuffer mensajeError){
		
		try {
			
			Boolean sinErrores = true;
			
			Long idGolesPartido = PartidoControllerDB.getInstance().getSiguienteIDGolesPartidoTransaccional(session);
			golesPartido.setGoles_partido(idGolesPartido);
			
			sinErrores = PartidoControllerDB.getInstance().crearGolesPartidoTransaccional(session, golesPartido) && sinErrores;
			
			if(sinErrores){
				
				return golesPartido;
			}else{
				
				mensajeError.append("Error creando el partido.");
				return null;
			}

		}catch (Exception e) {
			session.rollback();
			SimpleLogger.error("Error ", e);
			mensajeError.append("Error creando partido. No se ha podido finalizar correctamente.");
			
			return null;
		} 	
	}
	
	/**
	 * Se crea partido sin sede, sin fecha de programacion 
	 * 
	 * @param session
	 * @param partido
	 * @param mensajeError
	 * @return
	 */
	
	public Partido crearPartidoTransaccional(SqlSession session, Partido partido, StringBuffer mensajeError){
		
		try {
			
			Boolean sinErrores = true;
			
			Long idPartido = PartidoControllerDB.getInstance().getSiguienteIDPartidoTransaccional(session);
			partido.setPartido(idPartido);
			
			sinErrores = PartidoControllerDB.getInstance().crearPartidoTransaccional(session, partido) && sinErrores;
			
			if(sinErrores){
				
				return partido;
			}else{
				
				mensajeError.append("Error creando el partido.");
				return null;
			}

		}catch (Exception e) {
			session.rollback();
			SimpleLogger.error("Error ", e);
			mensajeError.append("Error creando partido. No se ha podido finalizar correctamente.");
			
			return null;
			
			
		} 	
		
		
		
	}
	
	/**
	 * Se crea partidoJuez
	 * 
	 * @param session
	 * @param partidoJuez
	 * @param mensajeError
	 * @return
	 */
	
	private PartidoJuez crearPartidoJuezTransaccional(SqlSession session, PartidoJuez partidoJuez, StringBuffer mensajeError){
		
		try {
			
			Boolean sinErrores = true;
			
			Long idPartidoJuez = PartidoControllerDB.getInstance().getSiguienteIDPartidoJuezTransaccional(session);
			partidoJuez.setPartido(idPartidoJuez);
			
			sinErrores = PartidoControllerDB.getInstance().crearPartidoJuezTransaccional(session, partidoJuez) && sinErrores;
			
			if(sinErrores){
				
				return partidoJuez;
			}else{
				
				mensajeError.append("Error creando partidoJuez.");
				return null;
			}

		}catch (Exception e) {
			session.rollback();
			SimpleLogger.error("Error ", e);
			mensajeError.append("Error creando partidoJuez. No se ha podido finalizar correctamente.");
			
			return null;
			
			
		} 	
		
		
		
	}
	
	/**
	 * Se crea tarjetasPartido
	 * 
	 * @param session
	 * @param partido
	 * @param mensajeError
	 * @return
	 */
	
	private TarjetasPartido crearTarjetasPartidoTransaccional(SqlSession session, TarjetasPartido tarjetasPartido, StringBuffer mensajeError){
		
		try {
			
			Boolean sinErrores = true;
			
			Long idTarjetasPartido = PartidoControllerDB.getInstance().getSiguienteIDPartidoTransaccional(session);
			tarjetasPartido.setTarjetas_partido(idTarjetasPartido);
			
			sinErrores = PartidoControllerDB.getInstance().crearTarjetasPartidoTransaccional(session, tarjetasPartido) && sinErrores;
			
			if(sinErrores){
				
				return tarjetasPartido;
			}else{
				
				mensajeError.append("Error creando  tarjetasPartido.");
				return null;
			}

		}catch (Exception e) {
			session.rollback();
			SimpleLogger.error("Error ", e);
			mensajeError.append("Error creando TarjetasPartido. No se ha podido finalizar correctamente.");
			
			return null;
			
			
		} 	
		
		
		
	}
	
	/**
	 * Se crea tirosPartido
	 * 
	 * @param session
	 * @param partido
	 * @param mensajeError
	 * @return
	 */
	
	private TirosPartido crearTirosPartidoTransaccional(SqlSession session, TirosPartido tirosPartido, StringBuffer mensajeError){
		
		try {
			
			Boolean sinErrores = true;
			
			Long idTirosPartido = PartidoControllerDB.getInstance().getSiguienteIDTirosPartidoTransaccional(session);
			tirosPartido.setPartido(idTirosPartido);
			
			sinErrores = PartidoControllerDB.getInstance().crearTirosPartidoTransaccional(session, tirosPartido) && sinErrores;
			
			if(sinErrores){
				
				return tirosPartido;
			}else{
				
				mensajeError.append("Error creando el partido.");
				return null;
			}

		}catch (Exception e) {
			session.rollback();
			SimpleLogger.error("Error ", e);
			mensajeError.append("Error creando partido. No se ha podido finalizar correctamente.");
			
			return null;
			
			
		} 	
		
		
		
	}
	
	
	
	public Boolean programarPartidosTransaccional(List<Partido> partidos, StringBuffer mensajeError){
		SqlSession session = DBManager.openSession();
		
		try {
			
			Boolean sinErrores = true;
			
			
			for (Partido partido : partidos) {
				
				//Se cambia el estado del partido a PROGRAMADO
				partido.setEstado(Partido.ESTADO_PROGRAMADO);
				
				sinErrores = PartidoControllerDB.getInstance().programarPartidoTransaccional(session, partido)&& sinErrores;
				
			}
			
			//Si no existen errores se finaliza la transaccion
			if(sinErrores){
				
				session.commit();
			}else{
				mensajeError.append("No fue posible realizar la programacion. Por favor intentelo nuevamente");
				session.rollback();
			}
						
			
			
			return sinErrores;

		}catch (Exception e) {
			session.rollback();
			SimpleLogger.error("Error ", e);
			mensajeError.append("Error creando grupo. No se ha podido finalizar correctamente.");
			
			return null;
			
			
		} 	finally {
			session.close();
		}
		
		
		
	}
	
	
	private void completarInformacionPartido(Partido partido){
		
		//Calcular informacion del grupo
		Grupo grupo = GrupoServicio.getInstance().getGrupo(partido.getGrupo());
		partido.setGrupoAsociado(grupo);
		
		//Se consulta los equipos
		Equipo equipoUno = EquipoServicio.getInstance().getEquipo(partido.getEquipo_1());
		partido.setEquipoUno(equipoUno);
		
		Equipo equipoDos = EquipoServicio.getInstance().getEquipo(partido.getEquipo_2());
		partido.setEquipoDos(equipoDos);
		
		//Se consulta la informacion de la sede
		
		if(partido.getSede()!=null){
			Sede sede = ParametrizacionServicio.getInstance().getSede(partido.getSede());
			partido.setSedeAsociada(sede);
		}
		
		//Goles
		List<GolesPartido> goles = PartidoControllerDB.getInstance().getGolesPartido(partido);
		List<GolesPartido> goles1 = new ArrayList<GolesPartido>();
		List<GolesPartido> goles2 = new ArrayList<GolesPartido>();
		
		for (GolesPartido golesPartido : goles) {
			List<Jugador> jugadoresEquipo1 = equipoUno.getJugadores();
			
			for (Jugador jugador : jugadoresEquipo1) {
				if(jugador.getJugador().equals(golesPartido.getJugador())){
					golesPartido.setJugadorAsociado(jugador.getNombre()+" "+jugador.getApellidos());
					goles1.add(golesPartido);
				}
			}
			
			List<Jugador> jugadoresEquipo2 = equipoDos.getJugadores();
			
			for (Jugador jugador : jugadoresEquipo2) {
				if(jugador.getJugador().equals(golesPartido.getJugador())){
					golesPartido.setJugadorAsociado(jugador.getNombre()+" "+jugador.getApellidos());
					goles2.add(golesPartido);
				}
			}
			
		}
		
		partido.setGoles1(goles1);
		partido.setGoles2(goles2);
		
		
		//tarjetas
		List<TarjetasPartido> tarjetas = PartidoControllerDB.getInstance().getTarjetasPartido(partido);
		List<TarjetasPartido> tarjetas1 = new ArrayList<TarjetasPartido>();
		List<TarjetasPartido> tarjetas2 = new ArrayList<TarjetasPartido>();
		
		for (TarjetasPartido tarjetasPartido : tarjetas) {
			List<Jugador> jugadoresEquipo1 = equipoUno.getJugadores();
			
			for (Jugador jugador : jugadoresEquipo1) {
				if(jugador.getJugador().equals(tarjetasPartido.getJugador())){
					tarjetasPartido.setJugadorAsociado(jugador.getNombre()+" "+jugador.getApellidos());
					tarjetas1.add(tarjetasPartido);
				}
			}
			
			List<Jugador> jugadoresEquipo2 = equipoDos.getJugadores();
			
			for (Jugador jugador : jugadoresEquipo2) {
				
				if(jugador.getJugador().equals(tarjetasPartido.getJugador())){
					tarjetasPartido.setJugadorAsociado(jugador.getNombre()+" "+jugador.getApellidos());
					tarjetas1.add(tarjetasPartido);
				}
			}
			
		}
		
		partido.setTarjetas1(tarjetas1);
		partido.setTarjetas2(tarjetas2);
		
	}
	

}
